package org.dromara.bclt.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.esotericsoftware.minlog.Log;
import lombok.extern.slf4j.Slf4j;
import org.dromara.bclt.domain.*;
import org.dromara.bclt.domain.bo.DeviceInfoBo;
import org.dromara.bclt.domain.vo.*;
import org.dromara.bclt.mapper.*;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.redis.utils.RedisUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.dromara.bclt.domain.bo.InferenceLogBo;
import org.dromara.bclt.service.IInferenceLogService;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 推理日志Service业务层处理
 *
 * @author RRyuan
 * @date 2025-05-12
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class InferenceLogServiceImpl implements IInferenceLogService {

    private static final Logger log = LoggerFactory.getLogger(InferenceLogServiceImpl.class);

    private final InferenceLogMapper baseMapper;
    private final CourseStatusMapper courseStatusMapper;
    private final CourseMapper courseMapper;
    private final DeviceInfoMapper deviceInfoMapper;
    private final DataScheduledMapper dataScheduledMapper;
    DateTime dayExerciseStartTime;
//    LocalDate  nowTime = LocalDate.now();
    LocalDateTime  nowTime;
//    LocalDateTime  nowTime = LocalDateTime.parse("2025-07-04T12:00:00");
    /**
     * 查询推理日志
     *
     * @param id 主键
     * @return 推理日志
     */
    @Override
    public InferenceLogVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询推理日志列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 推理日志分页列表
     */
    @Override
    public TableDataInfo<InferenceLogVo> queryPageList(InferenceLogBo bo, PageQuery pageQuery) {
        if(bo.getDeviceNumber() != null && bo.getCreateTime() != null && bo.getClient() == 1){
            // 1. 先查询设备ID
            DeviceInfoVo deviceInfoVo = deviceInfoMapper.selectVoOne(new LambdaQueryWrapper<DeviceInfo>()
                .select(DeviceInfo::getId)
                .eq(DeviceInfo::getDeviceNumber, bo.getDeviceNumber()));

            Long deviceId = null;
            if(deviceInfoVo != null){
                deviceId = deviceInfoVo.getId();
            }
            bo.setDeviceId(deviceId);
            System.out.println("日期： " + bo.getCreateTime());
            // 2. 查询指定时间之前的最近一条运动数据
            InferenceLogVo previousLog = baseMapper.selectVoOne(new LambdaQueryWrapper<InferenceLog>()
                .select(InferenceLog::getId, InferenceLog::getDayExerciseAverStartTime)
                .eq(InferenceLog::getDeviceId, bo.getDeviceId())
                .lt(InferenceLog::getCreateTime, bo.getCreateTime())
                .orderByDesc(InferenceLog::getCreateTime)
                .last("LIMIT 1"));
            System.out.println("previousLog = " + previousLog);
            if (previousLog != null) {
                System.out.println("在" + bo.getCreateTime() + "之前有运动数据");
                bo.setId(previousLog.getId());

            } else {
                System.out.println("在" + bo.getCreateTime() + "之前没有运动数据");
            }
        }
        if(bo.getDeviceNumber() != null) {
            DeviceInfoVo deviceInfoVo = deviceInfoMapper.selectVoOne(new LambdaQueryWrapper<DeviceInfo>()
                .select(DeviceInfo::getId)
                .eq(DeviceInfo::getDeviceNumber, bo.getDeviceNumber()));
            Long deviceId = null;
            if(deviceInfoVo != null){
                deviceId = deviceInfoVo.getId();
            }
            bo.setDeviceId(deviceId);
        }
        LambdaQueryWrapper<InferenceLog> lqw = buildQueryWrapper(bo);
        Page<InferenceLogVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的推理日志列表
     *
     * @param bo 查询条件
     * @return 推理日志列表
     */
    @Override
    public List<InferenceLogVo> queryList(InferenceLogBo bo) {
        LambdaQueryWrapper<InferenceLog> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<InferenceLog> buildQueryWrapper(InferenceLogBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<InferenceLog> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getDeviceId() != null, InferenceLog::getDeviceId, bo.getDeviceId());
        lqw.eq(StringUtils.isNotBlank(bo.getRuleIds()), InferenceLog::getRuleIds, bo.getRuleIds());
        lqw.eq(StringUtils.isNotBlank(bo.getContent()), InferenceLog::getContent, bo.getContent());
        lqw.eq(bo.getNoticeNumber() != null, InferenceLog::getNoticeNumber, bo.getNoticeNumber());
        lqw.eq(bo.getUnlearnOverDays() != null, InferenceLog::getUnlearnOverDays, bo.getUnlearnOverDays());
        lqw.eq(bo.getLearnStartAfterUpdateHour() != null, InferenceLog::getLearnStartAfterUpdateHour, bo.getLearnStartAfterUpdateHour());
        lqw.eq(bo.getLearnCompletionAfterUpdateDay() != null, InferenceLog::getLearnCompletionAfterUpdateDay, bo.getLearnCompletionAfterUpdateDay());
        lqw.eq(bo.getCourseCompletionNumber() != null, InferenceLog::getCourseCompletionNumber, bo.getCourseCompletionNumber());
        lqw.eq(bo.getCourseUncompletionNumber() != null, InferenceLog::getCourseUncompletionNumber, bo.getCourseUncompletionNumber());
        lqw.eq(bo.getWeekLearnCompletionRateBef0() != null, InferenceLog::getWeekLearnCompletionRateBef0, bo.getWeekLearnCompletionRateBef0());
        lqw.eq(bo.getAppRegisterDuration() != null, InferenceLog::getAppRegisterDuration, bo.getAppRegisterDuration());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef6() != null, InferenceLog::getDayInterfereIgnoreTimesBef6, bo.getDayInterfereIgnoreTimesBef6());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef5() != null, InferenceLog::getDayInterfereIgnoreTimesBef5, bo.getDayInterfereIgnoreTimesBef5());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef4() != null, InferenceLog::getDayInterfereIgnoreTimesBef4, bo.getDayInterfereIgnoreTimesBef4());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef3() != null, InferenceLog::getDayInterfereIgnoreTimesBef3, bo.getDayInterfereIgnoreTimesBef3());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef2() != null, InferenceLog::getDayInterfereIgnoreTimesBef2, bo.getDayInterfereIgnoreTimesBef2());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef1() != null, InferenceLog::getDayInterfereIgnoreTimesBef1, bo.getDayInterfereIgnoreTimesBef1());
        lqw.eq(bo.getDayInterfereIgnoreTimesBef0() != null, InferenceLog::getDayInterfereIgnoreTimesBef0, bo.getDayInterfereIgnoreTimesBef0());
        lqw.eq(bo.getDayInterfereResponsivityBef6() != null, InferenceLog::getDayInterfereResponsivityBef6, bo.getDayInterfereResponsivityBef6());
        lqw.eq(bo.getDayInterfereResponsivityBef5() != null, InferenceLog::getDayInterfereResponsivityBef5, bo.getDayInterfereResponsivityBef5());
        lqw.eq(bo.getDayInterfereResponsivityBef4() != null, InferenceLog::getDayInterfereResponsivityBef4, bo.getDayInterfereResponsivityBef4());
        lqw.eq(bo.getDayInterfereResponsivityBef3() != null, InferenceLog::getDayInterfereResponsivityBef3, bo.getDayInterfereResponsivityBef3());
        lqw.eq(bo.getDayInterfereResponsivityBef2() != null, InferenceLog::getDayInterfereResponsivityBef2, bo.getDayInterfereResponsivityBef2());
        lqw.eq(bo.getDayInterfereResponsivityBef1() != null, InferenceLog::getDayInterfereResponsivityBef1, bo.getDayInterfereResponsivityBef1());
        lqw.eq(bo.getDayInterfereResponsivityBef0() != null, InferenceLog::getDayInterfereResponsivityBef0, bo.getDayInterfereResponsivityBef0());
        lqw.eq(bo.getWeekExerciseCompletionRateBef3() != null, InferenceLog::getWeekExerciseCompletionRateBef3, bo.getWeekExerciseCompletionRateBef3());
        lqw.eq(bo.getWeekExerciseCompletionRateBef2() != null, InferenceLog::getWeekExerciseCompletionRateBef2, bo.getWeekExerciseCompletionRateBef2());
        lqw.eq(bo.getWeekExerciseCompletionRateBef1() != null, InferenceLog::getWeekExerciseCompletionRateBef1, bo.getWeekExerciseCompletionRateBef1());
        lqw.eq(bo.getWeekExerciseCompletionRateBef0() != null, InferenceLog::getWeekExerciseCompletionRateBef0, bo.getWeekExerciseCompletionRateBef0());
        lqw.eq(bo.getDayExercisePlanDoneBef6() != null, InferenceLog::getDayExercisePlanDoneBef6, bo.getDayExercisePlanDoneBef6());
        lqw.eq(bo.getDayExercisePlanDoneBef5() != null, InferenceLog::getDayExercisePlanDoneBef5, bo.getDayExercisePlanDoneBef5());
        lqw.eq(bo.getDayExercisePlanDoneBef4() != null, InferenceLog::getDayExercisePlanDoneBef4, bo.getDayExercisePlanDoneBef4());
        lqw.eq(bo.getDayExercisePlanDoneBef3() != null, InferenceLog::getDayExercisePlanDoneBef3, bo.getDayExercisePlanDoneBef3());
        lqw.eq(bo.getDayExercisePlanDoneBef2() != null, InferenceLog::getDayExercisePlanDoneBef2, bo.getDayExercisePlanDoneBef2());
        lqw.eq(bo.getDayExercisePlanDoneBef1() != null, InferenceLog::getDayExercisePlanDoneBef1, bo.getDayExercisePlanDoneBef1());
        lqw.eq(bo.getDayExercisePlanDoneBef0() != null, InferenceLog::getDayExercisePlanDoneBef0, bo.getDayExercisePlanDoneBef0());
        lqw.eq(bo.getBetweenDecisionLearnDuration() != null, InferenceLog::getBetweenDecisionLearnDuration, bo.getBetweenDecisionLearnDuration());
        lqw.eq(bo.getBetweenDecisionExerciseDuration() != null, InferenceLog::getBetweenDecisionExerciseDuration, bo.getBetweenDecisionExerciseDuration());
        lqw.eq(bo.getDayAmExerciseCompletionBef0() != null, InferenceLog::getDayAmExerciseCompletionBef0, bo.getDayAmExerciseCompletionBef0());
        lqw.eq(bo.getDayLowExerciseDurationBef0() != null, InferenceLog::getDayLowExerciseDurationBef0, bo.getDayLowExerciseDurationBef0());
        lqw.eq(bo.getDayMidExerciseDurationBef0() != null, InferenceLog::getDayMidExerciseDurationBef0, bo.getDayMidExerciseDurationBef0());
        lqw.eq(bo.getDayHighExerciseDurationBef0() != null, InferenceLog::getDayHighExerciseDurationBef0, bo.getDayHighExerciseDurationBef0());
        lqw.eq(bo.getDayAmExerciseDurationBef6() != null, InferenceLog::getDayAmExerciseDurationBef6, bo.getDayAmExerciseDurationBef6());
        lqw.eq(bo.getDayPmExerciseDurationBef6() != null, InferenceLog::getDayPmExerciseDurationBef6, bo.getDayPmExerciseDurationBef6());
        lqw.eq(bo.getDayAmExerciseDurationBef5() != null, InferenceLog::getDayAmExerciseDurationBef5, bo.getDayAmExerciseDurationBef5());
        lqw.eq(bo.getDayPmExerciseDurationBef5() != null, InferenceLog::getDayPmExerciseDurationBef5, bo.getDayPmExerciseDurationBef5());
        lqw.eq(bo.getDayAmExerciseDurationBef4() != null, InferenceLog::getDayAmExerciseDurationBef4, bo.getDayAmExerciseDurationBef4());
        lqw.eq(bo.getDayPmExerciseDurationBef4() != null, InferenceLog::getDayPmExerciseDurationBef4, bo.getDayPmExerciseDurationBef4());
        lqw.eq(bo.getDayAmExerciseDurationBef3() != null, InferenceLog::getDayAmExerciseDurationBef3, bo.getDayAmExerciseDurationBef3());
        lqw.eq(bo.getDayPmExerciseDurationBef3() != null, InferenceLog::getDayPmExerciseDurationBef3, bo.getDayPmExerciseDurationBef3());
        lqw.eq(bo.getDayAmExerciseDurationBef2() != null, InferenceLog::getDayAmExerciseDurationBef2, bo.getDayAmExerciseDurationBef2());
        lqw.eq(bo.getDayPmExerciseDurationBef2() != null, InferenceLog::getDayPmExerciseDurationBef2, bo.getDayPmExerciseDurationBef2());
        lqw.eq(bo.getDayAmExerciseDurationBef1() != null, InferenceLog::getDayAmExerciseDurationBef1, bo.getDayAmExerciseDurationBef1());
        lqw.eq(bo.getDayPmExerciseDurationBef1() != null, InferenceLog::getDayPmExerciseDurationBef1, bo.getDayPmExerciseDurationBef1());
        lqw.eq(bo.getDayAmExerciseDurationBef0() != null, InferenceLog::getDayAmExerciseDurationBef0, bo.getDayAmExerciseDurationBef0());
        lqw.eq(bo.getDayPmExerciseDurationBef0() != null, InferenceLog::getDayPmExerciseDurationBef0, bo.getDayPmExerciseDurationBef0());
        lqw.eq(bo.getDayStepBef6() != null, InferenceLog::getDayStepBef6, bo.getDayStepBef6());
        lqw.eq(bo.getDayStepBef5() != null, InferenceLog::getDayStepBef5, bo.getDayStepBef5());
        lqw.eq(bo.getDayStepBef4() != null, InferenceLog::getDayStepBef4, bo.getDayStepBef4());
        lqw.eq(bo.getDayStepBef3() != null, InferenceLog::getDayStepBef3, bo.getDayStepBef3());
        lqw.eq(bo.getDayStepBef2() != null, InferenceLog::getDayStepBef2, bo.getDayStepBef2());
        lqw.eq(bo.getDayStepBef1() != null, InferenceLog::getDayStepBef1, bo.getDayStepBef1());
        lqw.eq(bo.getDayStepBef0() != null, InferenceLog::getDayStepBef0, bo.getDayStepBef0());
        lqw.eq(bo.getDayExerciseCompletionRateBef6() != null, InferenceLog::getDayExerciseCompletionRateBef6, bo.getDayExerciseCompletionRateBef6());
        lqw.eq(bo.getDayExerciseCompletionRateBef5() != null, InferenceLog::getDayExerciseCompletionRateBef5, bo.getDayExerciseCompletionRateBef5());
        lqw.eq(bo.getDayExerciseCompletionRateBef4() != null, InferenceLog::getDayExerciseCompletionRateBef4, bo.getDayExerciseCompletionRateBef4());
        lqw.eq(bo.getDayExerciseCompletionRateBef3() != null, InferenceLog::getDayExerciseCompletionRateBef3, bo.getDayExerciseCompletionRateBef3());
        lqw.eq(bo.getDayExerciseCompletionRateBef2() != null, InferenceLog::getDayExerciseCompletionRateBef2, bo.getDayExerciseCompletionRateBef2());
        lqw.eq(bo.getDayExerciseCompletionRateBef1() != null, InferenceLog::getDayExerciseCompletionRateBef1, bo.getDayExerciseCompletionRateBef1());
        lqw.eq(bo.getDayExerciseCompletionRateBef0() != null, InferenceLog::getDayExerciseCompletionRateBef0, bo.getDayExerciseCompletionRateBef0());
        lqw.eq(bo.getExerciseStartAfterInterfereDuration() != null, InferenceLog::getExerciseStartAfterInterfereDuration, bo.getExerciseStartAfterInterfereDuration());
        lqw.eq(bo.getDayExerciseStartTime() != null, InferenceLog::getDayExerciseStartTime, bo.getDayExerciseStartTime());
        lqw.eq(bo.getExerciseUncompletionOverDays() != null, InferenceLog::getExerciseUncompletionOverDays, bo.getExerciseUncompletionOverDays());
        lqw.eq(bo.getDayExerciseAverStartTime() != null, InferenceLog::getDayExerciseAverStartTime, bo.getDayExerciseAverStartTime());
        lqw.eq(bo.getCurrentWeekExerciseIntensity() != null, InferenceLog::getCurrentWeekExerciseIntensity, bo.getCurrentWeekExerciseIntensity());
        lqw.eq(bo.getCurrentDayExerciseIntensity() != null, InferenceLog::getCurrentDayExerciseIntensity, bo.getCurrentDayExerciseIntensity());
        lqw.eq(bo.getCurrentExerciseWeekNumber() != null, InferenceLog::getCurrentExerciseWeekNumber, bo.getCurrentExerciseWeekNumber());
        lqw.eq(bo.getDailyInterventionRemindersCount() != null, InferenceLog::getDailyInterventionRemindersCount, bo.getDailyInterventionRemindersCount());
        lqw.eq(bo.getDailyInterventionSuccessRemindersCount() != null, InferenceLog::getDailyInterventionSuccessRemindersCount, bo.getDailyInterventionSuccessRemindersCount());
        lqw.eq(bo.getExerciseReminderCycle() != null, InferenceLog::getExerciseReminderCycle, bo.getExerciseReminderCycle());
        lqw.eq(bo.getCourseReminderCycle() != null, InferenceLog::getCourseReminderCycle, bo.getCourseReminderCycle());
        lqw.eq(bo.getDayAfterCourseUpdate() != null, InferenceLog::getDayAfterCourseUpdate, bo.getDayAfterCourseUpdate());
        lqw.eq(bo.getConsecutiveExerciseReminderIgnores() != null, InferenceLog::getConsecutiveExerciseReminderIgnores, bo.getConsecutiveExerciseReminderIgnores());
        lqw.eq(bo.getDailyExerInterventionSucCount() != null, InferenceLog::getDailyExerInterventionSucCount, bo.getDailyExerInterventionSucCount());
        lqw.eq(bo.getDailyCourseInterventionSucCount() != null, InferenceLog::getDailyCourseInterventionSucCount, bo.getDailyCourseInterventionSucCount());
        lqw.eq(bo.getDailyExerInterventionTotalCount() != null, InferenceLog::getDailyExerInterventionTotalCount, bo.getDailyExerInterventionTotalCount());
        lqw.eq(bo.getDailyCourseInterventionTotalCount() != null, InferenceLog::getDailyCourseInterventionTotalCount, bo.getDailyCourseInterventionTotalCount());
        lqw.eq(bo.getStopExerciseForSecurity() != null, InferenceLog::getStopExerciseForSecurity, bo.getStopExerciseForSecurity());

        return lqw;
    }

    /**
     * 新增推理日志
     *
     * @param bo 推理日志
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(InferenceLogBo bo) {
        InferenceLog add = MapstructUtils.convert(bo, InferenceLog.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改推理日志
     *
     * @param bo 推理日志
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(InferenceLogBo bo) {
        InferenceLog update = MapstructUtils.convert(bo, InferenceLog.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(InferenceLog entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除推理日志信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public InferenceLogBo InferenceData(DeviceInfoBo bo) {
        nowTime = LocalDateTime.now();
        InferenceLogBo newInferenceLog = new InferenceLogBo();
        // 获取当前时间戳
        System.out.println("nowTime = " + nowTime);
        System.out.println("LocalDateTime = " + nowTime);
        if (bo == null || bo.getDeviceNumber() == null) {
            throw new IllegalArgumentException("参数错误：设备编号为空");
        }
        //设备编号
        String deviceNumber = bo.getDeviceNumber();
        System.out.println("设备编号：" + deviceNumber);

        DeviceInfoVo deviceInfoVo =deviceInfoMapper.selectVoOne(new LambdaQueryWrapper<DeviceInfo>()
                    .eq(DeviceInfo::getDeviceNumber, deviceNumber));

        if (deviceInfoVo == null || deviceInfoVo.getCreateTime() == null) {
            throw new IllegalArgumentException("参数错误：设备编号为空");
        }
        long deviceid = deviceInfoVo.getId();
        //用户（设备）创建时间
        Date deviceCreateTime = deviceInfoVo.getCreateTime();

        // 设置设备ID
        newInferenceLog.setDeviceId(deviceid);
        newInferenceLog.setDeviceNumber(deviceNumber);


//        连续忽略运动提醒次数
        long consecutiveExerciseReminderIgnores = 0;
//        连续忽略课程提醒次数
        long consecutiveCourseReminderIgnores = 0;
//        当日运动干预成功提醒次数
        long dailyExerInterventionSucCount = 0;
//        当日课程干预成功提醒次数
        long dailyCourseInterventionSucCount = 0;
//        当日运动干预提醒总次数
        long dailyExerInterventionTotalCount = 0;
//        当日课程干预提醒总次数
        long dailyCourseInterventionTotalCount = 0;
//        下个决策点需判断是否干预成功
        long currentExerciseReminderStatus = 0;
        //运动不足提醒周期
        long exerciseReminderCycle = 2;
        //课程提醒周期
        long courseReminderCycle = 2;

        //触发安全问题停止运动推荐
        long stopExerciseForSecurity = 0;

        // 计算昨天0点和今天0点的时间
        LocalDate yesterday = LocalDate.from(nowTime.minusDays(1));

        LocalDateTime yesterdayStart = yesterday.atStartOfDay(); // 昨天00:00
        LocalDateTime todayStart = LocalDate.from(nowTime).atStartOfDay(); // 今天00:00

        // 转换为Date类型（假设数据库字段为Date类型）
        Date startTime = Date.from(yesterdayStart.atZone(ZoneId.systemDefault()).toInstant());
        Date endTime = Date.from(todayStart.atZone(ZoneId.systemDefault()).toInstant());

        // 查询昨天0点到今天0点之间的数据，按创建时间倒序排列
        List<InferenceLog> inferenceLogs = baseMapper.selectList(
            new LambdaQueryWrapper<InferenceLog>()
                .ge(InferenceLog::getCreateTime, startTime) // >= 昨天00:00
                .lt(InferenceLog::getCreateTime, endTime)    // < 今天00:00
                .orderByDesc(InferenceLog::getCreateTime)    // 按创建时间倒序
        );
        InferenceLog inferenceLog = null;
        if (inferenceLogs !=null && !inferenceLogs.isEmpty()){
            System.out.println("昨天的最后一条日志记录：" + inferenceLogs.get(0));
            inferenceLog = inferenceLogs.get(0);
            // 从昨天的最后一条记录中获取连续忽略次数
            consecutiveCourseReminderIgnores = inferenceLog.getConsecutiveCourseReminderIgnores();
            consecutiveExerciseReminderIgnores = inferenceLog.getConsecutiveExerciseReminderIgnores();
            exerciseReminderCycle = inferenceLog.getExerciseReminderCycle();
            courseReminderCycle = inferenceLog.getCourseReminderCycle();
        } else {
            System.out.println("当前记录为空");
            inferenceLog = new InferenceLog();
            // 如果没有昨天的记录，设置初始值为0
            consecutiveCourseReminderIgnores = 0L;
            consecutiveExerciseReminderIgnores = 0L;
        }
//      ---------------------------------------------------课程--------------------------------------------------------

        //课程更新时间
        Date courseUpdateTime;

        //当前是课程学习的第几周,也是APP使用为第X周
        long weeksSinceCreation = calculateWeeksSinceCreation(deviceCreateTime) + 1;
        System.out.println("当前是患者APP使用第" + weeksSinceCreation  + "周");

        //本周是第几运动周期
        long currentExerciseWeekNumber = -1;

        // 计算第一周的更新时间（使用设备创建时间）
        Calendar firstWeekCal = Calendar.getInstance();
        firstWeekCal.setTime(deviceCreateTime);
        // 保存第一周的时间部分（时分秒）
        int firstWeekHour = firstWeekCal.get(Calendar.HOUR_OF_DAY);
        int firstWeekMinute = firstWeekCal.get(Calendar.MINUTE);
        int firstWeekSecond = firstWeekCal.get(Calendar.SECOND);

        // 计算当前周的更新时间
        Calendar cal = Calendar.getInstance();
        cal.setTime(deviceCreateTime);
        // 设置与第一周相同的时间部分
        cal.set(Calendar.HOUR_OF_DAY, firstWeekHour);
        cal.set(Calendar.MINUTE, firstWeekMinute);
        cal.set(Calendar.SECOND, firstWeekSecond);
        // 如果不是第一周，则加上相应的周数
        if (weeksSinceCreation > 1) {
            cal.add(Calendar.WEEK_OF_YEAR, (int)weeksSinceCreation - 1);
        }
        courseUpdateTime = cal.getTime();
        System.out.println(" 设备id: " + deviceInfoVo.getId());

        //获取截至到某日的最新的记录
        InferenceLog lastInferenceLog = baseMapper.selectOne(
            new LambdaQueryWrapper<InferenceLog>()
                .eq(InferenceLog::getDeviceId, deviceInfoVo.getId())  // 使用 deviceInfoVo.getId() 替代 bo.getId()
                .le(InferenceLog::getCreateTime, nowTime) // 小于等于当日23:59:59
                .orderByDesc(InferenceLog::getCreateTime)
                .last("LIMIT 1")
        );
        System.out.println("lastInferenceLog = " + lastInferenceLog);
        // 检查最新记录是否是今天的记录
        boolean isTodayRecord = false;
        if (lastInferenceLog != null) {
            LocalDate recordDate = lastInferenceLog.getCreateTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
            isTodayRecord = recordDate.equals(nowTime.toLocalDate());
            System.out.println("recordDate = " + recordDate);
        }

        System.out.println("nowTime.toLocalDate() = " + nowTime.toLocalDate());
        System.out.println("isTodayRecord = " + isTodayRecord);
        if (lastInferenceLog != null && isTodayRecord) {
            System.out.println("查看上一条记录");
            if (lastInferenceLog.getCurrentExerciseWeekNumber() != null) {
                currentExerciseWeekNumber = lastInferenceLog.getCurrentExerciseWeekNumber();
            }
            if (lastInferenceLog.getDailyCourseInterventionTotalCount() != null) {
                System.out.println("上一条记录总提醒为：" + lastInferenceLog.getDailyCourseInterventionTotalCount());
                dailyCourseInterventionTotalCount = lastInferenceLog.getDailyCourseInterventionTotalCount();
            }
            if (lastInferenceLog.getDailyExerInterventionSucCount() != null) {
                dailyCourseInterventionSucCount = lastInferenceLog.getDailyCourseInterventionSucCount();
            }
            if (lastInferenceLog.getDailyExerInterventionTotalCount() != null) {
                dailyExerInterventionTotalCount = lastInferenceLog.getDailyExerInterventionTotalCount();
            }
            if (lastInferenceLog.getDailyExerInterventionSucCount() != null) {
                dailyExerInterventionSucCount = lastInferenceLog.getDailyExerInterventionSucCount();
            }
            if (lastInferenceLog.getConsecutiveCourseReminderIgnores() != null) {
                consecutiveCourseReminderIgnores = lastInferenceLog.getConsecutiveCourseReminderIgnores();
            }
            if (lastInferenceLog.getConsecutiveExerciseReminderIgnores() != null) {
                consecutiveExerciseReminderIgnores = lastInferenceLog.getConsecutiveExerciseReminderIgnores();
            }
            if (lastInferenceLog.getStopExerciseForSecurity() != null) {
                stopExerciseForSecurity = lastInferenceLog.getStopExerciseForSecurity();
            }
        } else {
            // 如果是今天第一次运动，初始化相关变量
            System.out.println("今天是第一次运动，初始化相关变量");
            currentExerciseWeekNumber = weeksSinceCreation;
            dailyCourseInterventionTotalCount = 0;
            dailyExerInterventionTotalCount = 0;
            dailyCourseInterventionSucCount = 0;
            dailyExerInterventionSucCount = 0;
//            consecutiveCourseReminderIgnores = 0;
//            consecutiveExerciseReminderIgnores = 0;

        }

        System.out.println("当前是第 " + currentExerciseWeekNumber + " 运动周期");



        //获取本周学习课程
        CourseVo courseVo = courseMapper.selectVoOne(new LambdaQueryWrapper<Course>()
                .eq(Course::getCourseOrder, weeksSinceCreation));
        System.out.println("本周学习课程："+ courseVo);
        if (courseVo == null || courseVo.getId() == null) {
            throw new IllegalArgumentException("参数错误：设备编号为空");
        }
        //获取当前课程的视频记录
        CourseStatusVo courseStatusVo = courseStatusMapper.selectVoOne(new LambdaQueryWrapper<CourseStatus>()
                .eq(CourseStatus::getDeviceId, deviceInfoVo.getId())
                .eq(CourseStatus::getCourseId, courseVo.getId()));

        System.out.println("本周课程的视频记录：" + courseStatusVo);
        System.out.println("本周学习课程的创建时间: " + courseUpdateTime);


        long dayAfterCourseUpdate = DateUtil.betweenDay(courseUpdateTime, DateUtil.date(nowTime), true) + 1;
        System.out.println("今天是课程更新后的第 " + dayAfterCourseUpdate + " 天");
        log.info("程序开始执行");
        log.info("当前时间：{}", DateUtil.date(nowTime));
        log.info("课程更新时间：{}", courseUpdateTime);
        log.info("今天是课程更新后的第 {} 天", dayAfterCourseUpdate);
        //本周学习课程记录的首次创建时间
        Date courseStatusCreateTime = null;
        //课程更新后X小时后开始学习, 计算课程更新后开始学习的小时数
        long learnStartAfterUpdateHour = -1;
        //课程更新后第X天完成学习, 计算课程更新后完成学习的天
        long learnCompletionAfterUpdateDay = -1;
        //课程学习完成数量为X
        long courseCompletionNumber = -1;
        //当周课程学习进度
        long weekLearnCompletionRateBef0 = -1;

        long courseUnlearnHour = -1;
        if (courseStatusVo == null) {
            System.out.println("课程未开始完成");
            courseUnlearnHour = Math.abs(Duration.between(
                courseUpdateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                nowTime
            ).toHours());
            System.out.println("课程未学习小时数：" + courseUnlearnHour);
            weekLearnCompletionRateBef0 = 0;
        }else {
            courseStatusCreateTime = courseStatusVo.getCreateTime();
            learnStartAfterUpdateHour = Math.abs(Duration.between(courseStatusCreateTime.toInstant() , courseUpdateTime.toInstant()).toHours());
            if (courseStatusVo.getFinishTime() == null) {
                learnCompletionAfterUpdateDay = -1;
                System.out.println("课程目前未完成学习！！");
            } else {
                learnCompletionAfterUpdateDay = Math.abs(Duration.between(courseStatusCreateTime.toInstant() ,courseStatusVo.getFinishTime().toInstant()).toDays());
            }
            weekLearnCompletionRateBef0 = courseStatusVo.getPlayProgress();
        }
        // 修改课程完成数量的计算逻辑
        courseCompletionNumber = courseStatusMapper.selectCount(new LambdaQueryWrapper<CourseStatus>()
            .lt(CourseStatus::getUpdateTime, nowTime)
            .eq(CourseStatus::getDeviceId, deviceInfoVo.getId())
            .eq(CourseStatus::getCourseStatus, "1"));  // 使用字符串"1"表示完成状态

        System.out.println("本周学习课程记录的首次创建时间: " + courseStatusCreateTime);
        System.out.println("课程更新后开始学习的小时数: " + learnStartAfterUpdateHour);
        System.out.println("课程更新后完成学习的天数: " + learnCompletionAfterUpdateDay);
        System.out.println("课程学习完成数量为: " + courseCompletionNumber);
        //课程学习未完成数量X
        long courseUncompletionNumber = -1;
        // 修改未完成课程数量的计算逻辑
        courseUncompletionNumber = weeksSinceCreation - courseCompletionNumber;

        System.out.println("课程学习未完成数量为: " + courseUncompletionNumber);
        System.out.println("当周课程学习进度: " + weekLearnCompletionRateBef0 + "%");

        // 获取当天步数数据
        long dayStepBef0 = getOneDayLastRecord(LocalDate.from(nowTime), deviceInfoVo);
        System.out.println("当天步数数据: " + dayStepBef0);


        // 获取最后一条课程状态记录
        List<CourseStatusVo> courseStatusVoList = courseStatusMapper.selectVoList(
                new LambdaQueryWrapper<CourseStatus>()
                .eq(CourseStatus::getDeviceId, deviceInfoVo.getId())
                .orderByDesc(CourseStatus::getCreateTime));

        //未学习的天数unlearnOverDays
        long unlearnOverDays = -1;
        if (courseStatusVoList != null && !courseStatusVoList.isEmpty()) {
            CourseStatusVo lastRecord = courseStatusVoList.get(0);
            if (lastRecord.getUpdateTime() != null) {
                LocalDate updateDate = lastRecord.getUpdateTime()
                        .toInstant()
                        .atZone(ZoneId.systemDefault())
                        .toLocalDate();

                unlearnOverDays = Math.abs(ChronoUnit.DAYS.between(updateDate, nowTime));
            }
        }else {
            unlearnOverDays = Math.abs(ChronoUnit.DAYS.between(deviceInfoVo.getCreateTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate(), nowTime));
        }
        System.out.println("未学习的天数: " + unlearnOverDays);




//      ---------------------------------------------------运动强度--------------------------------------------------------
//        TodayExerciseData todayData = calculateTodayExerciseDuration(deviceInfoVo, weeksSinceCreation);
        TodayExerciseData todayData = calculateTodayExerciseDuration(deviceInfoVo, currentExerciseWeekNumber);

// 获取上午数据
        ExercisePeriod morning = todayData.getMorning();
        System.out.println("上午运动数据:");
        System.out.println("  低强度: " + morning.getLowIntensityDuration() + "min");
        System.out.println("  中强度: " + morning.getMediumIntensityDuration() + "min");
        System.out.println("  高强度: " + morning.getHighIntensityDuration() + "min");
        System.out.println("  上午活动时长: " + morning.getTotalDuration() + "min");

        System.out.println("  完成率: " + morning.getCompletionRate() + "%");
        long dayAmExerciseCompletionBef0 = morning.getCompletionRate();
        long dayAmExerciseDurationBef0 = morning.getTotalDuration();
// 获取下午数据
        ExercisePeriod afternoon = todayData.getAfternoon();
        System.out.println("下午运动数据:");
        System.out.println("  低强度: " + afternoon.getLowIntensityDuration() + "min");
        System.out.println("  中强度: " + afternoon.getMediumIntensityDuration() + "min");
        System.out.println("  高强度: " + afternoon.getHighIntensityDuration() + "min");
        System.out.println("  下午活动时长: " + afternoon.getTotalDuration() + "min");

        System.out.println("  完成率: " + afternoon.getCompletionRate() + "%");
        long dayPmExerciseCompletionBef0 = afternoon.getCompletionRate();
        long dayPmExerciseDurationBef0 = afternoon.getTotalDuration();
        // 获取晚上数据
        ExercisePeriod evening = todayData.getEvening();
        System.out.println("晚上运动数据:");
        System.out.println("  低强度: " + evening.getLowIntensityDuration() + "min");
        System.out.println("  中强度: " + evening.getMediumIntensityDuration() + "min");
        System.out.println("  高强度: " + evening.getHighIntensityDuration() + "min");
        System.out.println("  晚上活动时长: " + evening.getTotalDuration() + "min");

        // 获取全天数据
        System.out.println("全天运动数据:");
        System.out.println("  总时长: " + todayData.getTotalDuration() + "min");
        System.out.println("  完成率: " + todayData.getTotalCompletionRate() + "%");

        //当日低强度运动时长
        long dayLowExerciseDurationBef0 = -1;
        dayLowExerciseDurationBef0 = morning.getLowIntensityDuration() + afternoon.getLowIntensityDuration() + evening.getLowIntensityDuration();
        System.out.println("当日低强度运动时长: " + dayLowExerciseDurationBef0 + "min");
        //当日中强度运动时长
        long dayMidExerciseDurationBef0 = -1;
        dayMidExerciseDurationBef0 = morning.getMediumIntensityDuration() + afternoon.getMediumIntensityDuration() + evening.getMediumIntensityDuration();
        System.out.println("当日中强度运动时长: " + dayMidExerciseDurationBef0 + "min");
        //当日高强度运动时长
        long dayHighExerciseDurationBef0 = -1;
        dayHighExerciseDurationBef0 = morning.getHighIntensityDuration() + afternoon.getHighIntensityDuration() + evening.getHighIntensityDuration();
        System.out.println("当日高强度运动时长: " + dayHighExerciseDurationBef0 + "min");

        //本周运动时长
        long weekExerciseDurationBef0 = -1;
        long weekExerciseDurationBef1 = -1;
        long weekExerciseDurationBef2 = -1;
        long weekExerciseDurationBef3 = -1;
        long weekExerciseDurationBef4 = -1;
        long weekExerciseDurationBef5 = -1;
        long weekExerciseDurationBef6 = -1;

        //仅七天每天运动时长
        long dayExerciseDurationBef0 = -1;
        long dayExerciseDurationBef1 = -1;
        long dayExerciseDurationBef2 = -1;
        long dayExerciseDurationBef3 = -1;
        long dayExerciseDurationBef4 = -1;
        long dayExerciseDurationBef5 = -1;
        long dayExerciseDurationBef6 = -1;

        dayExerciseDurationBef0 = dayLowExerciseDurationBef0 + dayMidExerciseDurationBef0 + dayHighExerciseDurationBef0;
        System.out.println("当日运动总时长：" + dayExerciseDurationBef0 + "分钟");

        long dayExerciseCompletionRateBef0 = -1;

        dayExerciseCompletionRateBef0 = todayData.getTotalCompletionRate();

        System.out.println("当日运动目标完成率：" + dayExerciseCompletionRateBef0+ "%");



        long currentWeekExerciseIntensity;
        if (currentExerciseWeekNumber <= 2) {
            currentWeekExerciseIntensity = 45;
        } else if (currentExerciseWeekNumber <= 4) {
            currentWeekExerciseIntensity = 60;// 第3-4周：60分钟/周
        } else if (currentExerciseWeekNumber <= 6) {
            currentWeekExerciseIntensity = 90;// 第5-6周：90分钟/周
        } else if (currentExerciseWeekNumber <= 8) {
            currentWeekExerciseIntensity = 120;// 第7-8周：120分钟/周
        } else {
            currentWeekExerciseIntensity = 150;// 第9周及以上：150分钟/周
        }
        System.out.println("本周的运动达标强度为：" + currentWeekExerciseIntensity + " 分钟");


        //,按照上午目标完成率判断
        long dayExercisePlanDoneBef0 = 0;
        if(dayExerciseCompletionRateBef0 >= 100 & dayExercisePlanDoneBef0 != -1){
            dayExercisePlanDoneBef0 = 1;
        }
        System.out.println("当日是否提前完成当日运动计划: " + dayExercisePlanDoneBef0);


//      ---------------------------------------------------干预提醒--------------------------------------------------------

        long exerciseStartAfterInterfereDuration = -1;
        long betweenDecisionLearnDuration = -1;
        long betweenDecisionExerciseDuration = -1;
//        当日所有干预提醒次数
        long dailyInterventionRemindersCount = -1;
//        当日所有成功干预提醒次数
        long dailyInterventionSuccessRemindersCount = -1;

        long noticeNumber = -1;

        int hour = LocalTime.now().getHour();

        // 根据当前时间设置通知编号
        if (hour == 8) {
            noticeNumber = 1;
        } else if (hour == 12) {
            noticeNumber = 2;
        } else if (hour == 16) {
            noticeNumber = 3;
        } else if (hour == 20) {
            noticeNumber = 4;
        }
        System.out.println("当前小时为：" + hour);

//        if (noticeNumber != 4 && exerciseReminderCycle == 0) {
//            exerciseReminderCycle = -1;
//        }else if (noticeNumber == 4) {
//            if (exerciseReminderCycle == 0) {
//                exerciseReminderCycle = 1;
//            }else if (exerciseReminderCycle == 1){
//                exerciseReminderCycle = 0;
//            }
//        }
        if (noticeNumber == 4 && exerciseReminderCycle != 2) {
            exerciseReminderCycle = (exerciseReminderCycle + 1) % 2; //数学计算 -1->0, 0->1, 1->0
        }
        //2代表正常状态，1表示隔天推送状态下的推送，0表示隔天推送状态下的不推送，-1表示今天要推完
        if (noticeNumber == 4 && courseReminderCycle != 2) {
            courseReminderCycle = (courseReminderCycle + 1) % 2; //数学计算 -1->0, 0->1, 1->0
        }

        Integer valueForExercise = RedisUtils.getCacheObject(bo.getDeviceNumber() + "currentExerciseReminderStatus");
        if (valueForExercise != null) {
            currentExerciseReminderStatus = valueForExercise;
        }
        System.out.println("当前是否需要检测运动反馈情况: " + currentExerciseReminderStatus);

        if (currentExerciseReminderStatus == 1) {
            System.out.println("查看运动干预结果");
            System.out.println("dailyExerInterventionTotalCount = " + dailyExerInterventionTotalCount);
            dailyExerInterventionTotalCount += 1;
            if (noticeNumber == 3) {
                //判断12：00-18：00之间是否有低中高强度运动，运动时长是多少
                LocalDateTime exerciseStartTime = nowTime.withHour(12).withMinute(0).withSecond(0);
                LocalDateTime exerciseEndTime = nowTime.withHour(16).withMinute(0).withSecond(0);
                long result = isExerciseInterventionResponded(exerciseStartTime, exerciseEndTime, deviceInfoVo);
                if(result >= 15) {
                    //每日运动干预提醒次数＋1
                    dailyExerInterventionSucCount += 1;
                    consecutiveExerciseReminderIgnores = 0;
                } else {
                    //连续忽略提醒次数＋1
                    consecutiveExerciseReminderIgnores += 1;
                }
                System.out.println("当日运动干预总提醒次数: " + dailyExerInterventionTotalCount);
                System.out.println("当日运动干预成功提醒次数: " + dailyExerInterventionSucCount);
            }
            else if (noticeNumber == 4) {
                //判断12：00-18：00之间是否有低中高强度运动，运动时长是多少
                LocalDateTime exerciseStartTime = nowTime.withHour(16).withMinute(0).withSecond(0);
                LocalDateTime exerciseEndTime = nowTime.withHour(19).withMinute(0).withSecond(0);
                long result = isExerciseInterventionResponded(exerciseStartTime, exerciseEndTime, deviceInfoVo);
                System.out.println("consecutiveExerciseReminderIgnores = " + consecutiveExerciseReminderIgnores);
                if(result >= 15) {
                    //每日运动干预提醒次数＋1
                    dailyExerInterventionSucCount += 1;
                    consecutiveExerciseReminderIgnores = 0;
                } else {
                    //连续忽略提醒次数＋1
                    consecutiveExerciseReminderIgnores += 1;
                    if (consecutiveExerciseReminderIgnores == 6) {
                        exerciseReminderCycle = 0;
                        System.out.println("连续六次运动未响应，隔天推送运动干预");
                    }
                }
                valueForExercise = 0;
                RedisUtils.setCacheObject(bo.getDeviceNumber() + "currentExerciseReminderStatus", valueForExercise);

            }
            //判断是否响应之后需要将状态重置为0
            currentExerciseReminderStatus = 0;
        }
        System.out.println("exerciseReminderCycle = " + exerciseReminderCycle);
        if (exerciseReminderCycle == 0) {
            System.out.println("当前是隔天不推送运动");
        }else if (exerciseReminderCycle == 1){
            System.out.println("当前是隔天推送运动");
        }
        System.out.println("courseReminderCycle = " + courseReminderCycle);
        if (courseReminderCycle == 0) {
            System.out.println("当前是隔天不推送课程");
        }else if (courseReminderCycle == 1){
            System.out.println("当前是隔天推送课程");
        }
        long currentCourseReminderStatus = 0;
        Integer valueForCourse = RedisUtils.getCacheObject(bo.getDeviceNumber() + "currentCourseReminderStatus");
        System.out.println("这里的valueForCourse: " + valueForCourse);
        if (valueForCourse != null) {
            currentCourseReminderStatus = valueForCourse;
        }
        System.out.println("当前是否需要检测课程反馈情况: " + currentCourseReminderStatus);
        System.out.println("dailyCourseInterventionTotalCount = " + dailyCourseInterventionTotalCount);
        if (currentCourseReminderStatus == 1) {
            boolean hasValidLearning = false;
            dailyCourseInterventionTotalCount += 1;
            if (noticeNumber == 2) {
                // 设置时间范围：9:00-12:00
                LocalDateTime courseStartTime = nowTime.withHour(9).withMinute(0).withSecond(0);
                LocalDateTime courseEndTime = nowTime.withHour(12).withMinute(0).withSecond(0);
                hasValidLearning = isCourseInterventionResponed(courseStartTime, courseEndTime, deviceInfoVo);

            } else if (noticeNumber == 3) {
                // 设置时间范围：12:00-18:00
                LocalDateTime courseStartTime = nowTime.withHour(12).withMinute(0).withSecond(0);
                LocalDateTime courseEndTime = nowTime.withHour(16).withMinute(0).withSecond(0);
                hasValidLearning = isCourseInterventionResponed(courseStartTime, courseEndTime, deviceInfoVo);
            }
            else if (noticeNumber == 4) {
                // 设置时间范围：18:00-19:00
                LocalDateTime courseStartTime = nowTime.withHour(16).withMinute(0).withSecond(0);
                LocalDateTime courseEndTime = nowTime.withHour(19).withMinute(0).withSecond(0);
                hasValidLearning = isCourseInterventionResponed(courseStartTime, courseEndTime, deviceInfoVo);
                valueForCourse = 0;
                RedisUtils.setCacheObject(bo.getDeviceNumber() + "currentCourseReminderStatus", valueForCourse); //0 或 1
            }
            if (hasValidLearning) {
                System.out.println("干预成功：用户在两次提醒期间有超过3分钟的课程学习记录");
                dailyCourseInterventionSucCount += 1;
                consecutiveCourseReminderIgnores = 0;
            } else {
                consecutiveCourseReminderIgnores += 1;
            }
            currentCourseReminderStatus = 0;
            System.out.println("当日课程干预总提醒次数: " + dailyCourseInterventionTotalCount);
            System.out.println("当日课程干预成功提醒次数: " + dailyCourseInterventionSucCount);

        }
        if (consecutiveCourseReminderIgnores == 6 && noticeNumber == 4) {
            courseReminderCycle = 0;
            System.out.println("连续六次课程未响应，隔天推送课程干预");
        }

        RedisUtils.setCacheObject(bo.getDeviceNumber() + "currentExerciseReminderStatus", currentExerciseReminderStatus); //0 或 1
        RedisUtils.setCacheObject(bo.getDeviceNumber() + "currentCourseReminderStatus", currentCourseReminderStatus); //0 或 1



        dailyInterventionRemindersCount = dailyExerInterventionTotalCount + dailyCourseInterventionTotalCount;
        System.out.println("每日总干预次数: " + dailyInterventionRemindersCount);
        dailyInterventionSuccessRemindersCount = dailyCourseInterventionSucCount + dailyExerInterventionSucCount;
        System.out.println("每日成功干预次数: " + dailyInterventionSuccessRemindersCount);
        System.out.println("连续忽略运动提醒次数: " + consecutiveExerciseReminderIgnores);
        System.out.println("连续忽略课程提醒次数: " + consecutiveCourseReminderIgnores);

//      ---------------------------------------------------获取历史推理日志--------------------------------------------------------

        //前六天目标完全率
        long dayExerciseCompletionRateBef1 = -1;
        long dayExerciseCompletionRateBef2 = -1;
        long dayExerciseCompletionRateBef3 = -1;
        long dayExerciseCompletionRateBef4 = -1;
        long dayExerciseCompletionRateBef5 = -1;
        long dayExerciseCompletionRateBef6 = -1;


        //根据昨晚的最后一条记录，复用前六天的数据
        if(inferenceLog.getDayExerciseCompletionRateBef0() != null){
            dayExerciseCompletionRateBef1 = inferenceLog.getDayExerciseCompletionRateBef0();
        }
        if (inferenceLog.getDayExerciseCompletionRateBef1() != null){
            dayExerciseCompletionRateBef2 = inferenceLog.getDayExerciseCompletionRateBef1();
        }
        if (inferenceLog.getDayExerciseCompletionRateBef2() != null){
            dayExerciseCompletionRateBef3 = inferenceLog.getDayExerciseCompletionRateBef2();
        }
        if (inferenceLog.getDayExerciseCompletionRateBef3() != null){
            dayExerciseCompletionRateBef4 = inferenceLog.getDayExerciseCompletionRateBef3();
        }
        if (inferenceLog.getDayExerciseCompletionRateBef4() != null){
            dayExerciseCompletionRateBef5 = inferenceLog.getDayExerciseCompletionRateBef4();
        }
        if (inferenceLog.getDayExerciseCompletionRateBef5() != null){
            dayExerciseCompletionRateBef6 = inferenceLog.getDayExerciseCompletionRateBef5();
        }

        System.out.println("前1天的运动完成率："+ dayExerciseCompletionRateBef1);

        //前六天上午活动时长
        long dayAmExerciseDurationBef1 = -1;
        long dayAmExerciseDurationBef2 = -1;
        long dayAmExerciseDurationBef3 = -1;
        long dayAmExerciseDurationBef4 = -1;
        long dayAmExerciseDurationBef5 = -1;
        long dayAmExerciseDurationBef6 = -1;

        if (inferenceLog.getDayAmExerciseDurationBef0() != null){
            dayAmExerciseDurationBef1 = inferenceLog.getDayAmExerciseDurationBef0();
        }
        if (inferenceLog.getDayAmExerciseDurationBef1() != null){
            dayAmExerciseDurationBef2 = inferenceLog.getDayAmExerciseDurationBef1();
        }
        if (inferenceLog.getDayAmExerciseDurationBef2() != null){
            dayAmExerciseDurationBef2 = inferenceLog.getDayAmExerciseDurationBef2();
        }
        if (inferenceLog.getDayAmExerciseDurationBef3() != null){
            dayAmExerciseDurationBef4 = inferenceLog.getDayAmExerciseDurationBef3();
        }
        if (inferenceLog.getDayAmExerciseDurationBef4() != null){
            dayAmExerciseDurationBef5 = inferenceLog.getDayAmExerciseDurationBef4();
        }
        if (inferenceLog.getDayAmExerciseDurationBef5() != null){
            dayAmExerciseDurationBef6 = inferenceLog.getDayAmExerciseDurationBef5();
        }
        //前六天下午活动时长
        long dayPmExerciseDurationBef1 = -1;
        long dayPmExerciseDurationBef2 = -1;
        long dayPmExerciseDurationBef3 = -1;
        long dayPmExerciseDurationBef4 = -1;
        long dayPmExerciseDurationBef5 = -1;
        long dayPmExerciseDurationBef6 = -1;

        if (inferenceLog.getDayPmExerciseDurationBef0() != null){
            dayPmExerciseDurationBef1 = inferenceLog.getDayPmExerciseDurationBef0();
        }
        if (inferenceLog.getDayPmExerciseDurationBef1() != null){
            dayPmExerciseDurationBef2 = inferenceLog.getDayPmExerciseDurationBef1();
        }
        if (inferenceLog.getDayPmExerciseDurationBef2() != null){
            dayPmExerciseDurationBef3 = inferenceLog.getDayPmExerciseDurationBef2();
        }
        if (inferenceLog.getDayPmExerciseDurationBef3() != null){
            dayPmExerciseDurationBef4 = inferenceLog.getDayPmExerciseDurationBef3();
        }
        if (inferenceLog.getDayPmExerciseDurationBef4() != null){
            dayPmExerciseDurationBef5 = inferenceLog.getDayPmExerciseDurationBef4();
        }
        if (inferenceLog.getDayPmExerciseDurationBef5() != null){
            dayPmExerciseDurationBef6 = inferenceLog.getDayPmExerciseDurationBef5();
        }

        //前一天的运动时长
        if (dayAmExerciseDurationBef1 != -1 & dayPmExerciseDurationBef1 != -1) {
            dayExerciseDurationBef1 = dayAmExerciseDurationBef1 + dayPmExerciseDurationBef1;
        }else{
            dayExerciseDurationBef1 = -1;
        }
        if (dayAmExerciseDurationBef2 != -1 & dayPmExerciseDurationBef2 != -1) {
            dayExerciseDurationBef2 = dayAmExerciseDurationBef2 + dayPmExerciseDurationBef2;
        }else{
            dayExerciseDurationBef2 = -1;
        }if (dayAmExerciseDurationBef3 != -1 & dayPmExerciseDurationBef3 != -1) {
            dayExerciseDurationBef3 = dayAmExerciseDurationBef3 + dayPmExerciseDurationBef3;
        }else{
            dayExerciseDurationBef3 = -1;
        }if (dayAmExerciseDurationBef4 != -1 & dayPmExerciseDurationBef4 != -1) {
            dayExerciseDurationBef4 = dayAmExerciseDurationBef4 + dayPmExerciseDurationBef4;
        }else{
            dayExerciseDurationBef4 = -1;
        }
        if (dayAmExerciseDurationBef5 != -1 & dayPmExerciseDurationBef5 != -1) {
            dayExerciseDurationBef5 = dayAmExerciseDurationBef5 + dayPmExerciseDurationBef5;
        }else{
            dayExerciseDurationBef5 = -1;
        }
        if (dayAmExerciseDurationBef6 != -1 & dayPmExerciseDurationBef6 != -1) {
            dayExerciseDurationBef6 = dayAmExerciseDurationBef6 + dayPmExerciseDurationBef6;
        }else{
            dayExerciseDurationBef6 = -1;
        }



        //六天前的干预响应率
        long dayInterfereResponsivityBef6 = -1;
        long dayInterfereResponsivityBef5 = -1;
        long dayInterfereResponsivityBef4 = -1;
        long dayInterfereResponsivityBef3 = -1;
        long dayInterfereResponsivityBef2 = -1;
        long dayInterfereResponsivityBef1 = -1;
        long dayInterfereResponsivityBef0 = -1;

        if (inferenceLog.getDayInterfereResponsivityBef0() != null){
            dayInterfereResponsivityBef1 = inferenceLog.getDayInterfereResponsivityBef0();
        }if (inferenceLog.getDayInterfereResponsivityBef1() != null){
            dayInterfereResponsivityBef2 = inferenceLog.getDayInterfereResponsivityBef1();
        }if (inferenceLog.getDayInterfereResponsivityBef2() != null){
            dayInterfereResponsivityBef3 = inferenceLog.getDayInterfereResponsivityBef2();
        }if (inferenceLog.getDayInterfereResponsivityBef3() != null){
            dayInterfereResponsivityBef4 = inferenceLog.getDayInterfereResponsivityBef3();
        }if (inferenceLog.getDayInterfereResponsivityBef4() != null){
            dayInterfereResponsivityBef5 = inferenceLog.getDayInterfereResponsivityBef4();
        }if (inferenceLog.getDayInterfereResponsivityBef5() != null){
            dayInterfereResponsivityBef6 = inferenceLog.getDayInterfereResponsivityBef5();
        }


        //6天前忽略运动提醒次数
        long dayInterfereIgnoreTimesBef6 = -1;
        long dayInterfereIgnoreTimesBef5 = -1;
        long dayInterfereIgnoreTimesBef4 = -1;
        long dayInterfereIgnoreTimesBef3 = -1;
        long dayInterfereIgnoreTimesBef2 = -1;
        long dayInterfereIgnoreTimesBef1 = -1;
        long dayInterfereIgnoreTimesBef0 = -1;
        if (inferenceLog.getDayInterfereIgnoreTimesBef0() != null){
            dayInterfereIgnoreTimesBef1 = inferenceLog.getDayInterfereIgnoreTimesBef0();
        }if (inferenceLog.getDayInterfereIgnoreTimesBef1() != null){
            dayInterfereIgnoreTimesBef2 = inferenceLog.getDayInterfereIgnoreTimesBef1();
        }if (inferenceLog.getDayInterfereIgnoreTimesBef2() != null){
            dayInterfereIgnoreTimesBef3 = inferenceLog.getDayInterfereIgnoreTimesBef2();
        }if (inferenceLog.getDayInterfereIgnoreTimesBef3() != null){
            dayInterfereIgnoreTimesBef4 = inferenceLog.getDayInterfereIgnoreTimesBef3();
        }if (inferenceLog.getDayInterfereIgnoreTimesBef4() != null){
            dayInterfereIgnoreTimesBef5 = inferenceLog.getDayInterfereIgnoreTimesBef4();
        }if (inferenceLog.getDayInterfereIgnoreTimesBef5() != null){
            dayInterfereIgnoreTimesBef6 = inferenceLog.getDayInterfereIgnoreTimesBef5();
        }
        //6天前步数
        long dayStepBef1 = -1;
        long dayStepBef2 = -1;
        long dayStepBef3 = -1;
        long dayStepBef4 = -1;
        long dayStepBef5 = -1;
        long dayStepBef6 = -1;
        if (inferenceLog.getDayStepBef0() != null){
            dayStepBef1 = inferenceLog.getDayStepBef0();
        }if (inferenceLog.getDayStepBef1() != null){
            dayStepBef2 = inferenceLog.getDayStepBef1();
        }if (inferenceLog.getDayStepBef2() != null){
            dayStepBef3 = inferenceLog.getDayStepBef2();
        }if (inferenceLog.getDayStepBef3() != null){
            dayStepBef4 = inferenceLog.getDayStepBef3();
        }if (inferenceLog.getDayStepBef4() != null){
            dayStepBef5 = inferenceLog.getDayStepBef4();
        }if (inferenceLog.getDayStepBef5() != null){
            dayStepBef6 = inferenceLog.getDayStepBef5();
        }

        long weekExerciseCompletionRateBef1 = -1;
        long weekExerciseCompletionRateBef2 = -1;
        long weekExerciseCompletionRateBef3 = -1;
        if(dayAfterCourseUpdate == 1 && noticeNumber == 1) {
            if (inferenceLog.getWeekExerciseCompletionRateBef0() != null){
                weekExerciseCompletionRateBef1 = inferenceLog.getWeekExerciseCompletionRateBef0();
            }if (inferenceLog.getWeekExerciseCompletionRateBef1() != null){
                weekExerciseCompletionRateBef2 = inferenceLog.getWeekExerciseCompletionRateBef1();
            }if (inferenceLog.getWeekExerciseCompletionRateBef2() != null){
                weekExerciseCompletionRateBef3 = inferenceLog.getWeekExerciseCompletionRateBef2();
            }
        }


        long dayExercisePlanDoneBef1 = -1;
        long dayExercisePlanDoneBef2 = -1;
        long dayExercisePlanDoneBef3 = -1;
        long dayExercisePlanDoneBef4 = -1;
        long dayExercisePlanDoneBef5 = -1;
        long dayExercisePlanDoneBef6 = -1;
        if (inferenceLog.getDayExercisePlanDoneBef0() != null){
            dayExercisePlanDoneBef1 = inferenceLog.getDayExercisePlanDoneBef0();
        }if (inferenceLog.getDayExercisePlanDoneBef1() != null){
            dayExercisePlanDoneBef2 = inferenceLog.getDayExercisePlanDoneBef1();
        }if (inferenceLog.getDayExercisePlanDoneBef2() != null){
            dayExercisePlanDoneBef3 = inferenceLog.getDayExercisePlanDoneBef2();
        }if (inferenceLog.getDayExercisePlanDoneBef3() != null){
            dayExercisePlanDoneBef4 = inferenceLog.getDayExercisePlanDoneBef3();
        }if (inferenceLog.getDayExercisePlanDoneBef4() != null){
            dayExercisePlanDoneBef5 = inferenceLog.getDayExercisePlanDoneBef4();
        }if (inferenceLog.getDayExercisePlanDoneBef5() != null){
            dayExercisePlanDoneBef6 = inferenceLog.getDayExercisePlanDoneBef5();
        }

        long exerciseUncompletionOverDays = -1;
        if (inferenceLog.getExerciseUncompletionOverDays() != null){

            System.out.println("dayExerciseCompletionRateBef0 = " + dayExerciseCompletionRateBef0);
            if (dayExerciseCompletionRateBef0 >= 100 ) {
                exerciseUncompletionOverDays = 0;
            } else {
                exerciseUncompletionOverDays =  inferenceLog.getExerciseUncompletionOverDays() + 1;
            }
        }

        //求当前记录的平均开始学习时间
        // 查询所有记录的 day_execise_start_time 列，返回 Date 列表
        List<LocalDateTime> startTimeList = baseMapper.selectObjs(
                new LambdaQueryWrapper<InferenceLog>()
                    .select(InferenceLog::getDayExerciseStartTime)
                    .eq(InferenceLog::getDelFlag, 0) // 添加过滤条件（如果需要）
                    .eq(InferenceLog::getDeviceId, deviceid)
            ).stream()
            .filter(Objects::nonNull) // 过滤可能的 null 值
            .map(obj -> (LocalDateTime) obj)   // 将 Object 转换为 Date
            .collect(Collectors.toList());
        System.out.println("startTimeList = " + startTimeList);
        Optional<LocalDateTime> averageStartTime = Optional.empty();
        if (startTimeList != null && !startTimeList.isEmpty()){
            // 现在可以计算平均时间
            averageStartTime = calculateAverage(startTimeList);        // 输出结果
            // 定义统一格式（移除 T，用空格分隔）
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            System.out.println("平均开始运动时间: " + (averageStartTime.isPresent() ? averageStartTime.get().format(formatter) : "无有效数据"));

            // 新增：判断今天的开始运动时间是否晚于平均开始运动时间（只比较时间部分）
            if (dayExerciseStartTime != null && averageStartTime.isPresent()) {
                LocalTime todayTime = dayExerciseStartTime.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
                LocalTime avgTime = averageStartTime.get().toLocalTime();
                boolean isLater = todayTime.isAfter(avgTime);
                System.out.println("今天的开始运动时间" + todayTime + (isLater ? " 晚于 " : " 早于或等于 ") + "平均开始运动时间" + avgTime);
            }
            if (noticeNumber == 4) {
                // 1. 查询所有历史非空运动开始时间
                List<LocalDateTime> historyStartTimes = baseMapper.selectObjs(
                        new LambdaQueryWrapper<InferenceLog>()
                            .select(InferenceLog::getDayExerciseStartTime)
                            .eq(InferenceLog::getDelFlag, 0)
                            .isNotNull(InferenceLog::getDayExerciseStartTime)
                    ).stream()
                    .filter(Objects::nonNull)
                    .map(obj -> {
                        if (obj instanceof LocalDateTime) return (LocalDateTime) obj;
                        if (obj instanceof Date) return ((Date)obj).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        if (obj instanceof DateTime) return ((DateTime)obj).toLocalDateTime();
                        return null;
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

                // 2. 今日有运动则加上今日
                if (dayExerciseStartTime != null) {
                    // dayExerciseStartTime 可能是 DateTime 类型，转为 LocalDateTime
                    LocalDateTime todayStartTime = null;
                    if (dayExerciseStartTime instanceof DateTime) {
                        todayStartTime = ((DateTime)dayExerciseStartTime).toLocalDateTime();
                    } else if (dayExerciseStartTime instanceof Date) {
                        todayStartTime = ((Date)dayExerciseStartTime).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    }
                    if (todayStartTime != null) {
                        historyStartTimes.add(todayStartTime);
                    }
                }

                // 3. 计算平均
                Optional<LocalDateTime> avgStartTime = calculateAverage(historyStartTimes);
//            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                System.out.println("到今天为止的平均运动开始时间: " + (avgStartTime.isPresent() ? avgStartTime.get().format(formatter) : "无有效数据"));


            }
        }
        System.out.println("今日开始运动时间：" + dayExerciseStartTime);
        if (noticeNumber == 4) {
            //第四次计算时需要把安全问题停止运动推荐的状态改为0，不影响第二天的推送
            stopExerciseForSecurity = 0;
        }
        if (dailyInterventionRemindersCount != 0) {
            dayInterfereResponsivityBef0 = dailyInterventionSuccessRemindersCount * 100 / dailyInterventionRemindersCount;
        } else {
            dayInterfereResponsivityBef0 = 0;
        }
        System.out.println("当日干预响应率：" + dayInterfereResponsivityBef0 + "%");
        // 计算近7天总运动时长（分钟）
        long totalWeeklyDuration = -1;
        //---------------------------------------------------本周的运动情况-------------------------------------------------------
        switch ((int) dayAfterCourseUpdate){
            case 1:
                totalWeeklyDuration = dayExerciseDurationBef0; break;
            case 2:
                totalWeeklyDuration = dayExerciseDurationBef0 + dayExerciseDurationBef1; break;
            case 3:
                totalWeeklyDuration = dayExerciseDurationBef0 + dayExerciseDurationBef1 + dayExerciseDurationBef2; break;
            case 4:
                totalWeeklyDuration = dayExerciseDurationBef0 + dayExerciseDurationBef1 + dayExerciseDurationBef2 + dayExerciseDurationBef3; break;
            case 5:
                totalWeeklyDuration = dayExerciseDurationBef0 + dayExerciseDurationBef1 + dayExerciseDurationBef2 + dayExerciseDurationBef3 +dayExerciseDurationBef4;
                break;
            case 6:
                totalWeeklyDuration = (dayExerciseDurationBef0 +
                    dayExerciseDurationBef1 +
                    dayExerciseDurationBef2 +
                    dayExerciseDurationBef3 +
                    dayExerciseDurationBef4 +
                    dayExerciseDurationBef5); break;
            case 7:
                totalWeeklyDuration = (dayExerciseDurationBef0 +
                    dayExerciseDurationBef1 +
                    dayExerciseDurationBef2 +
                    dayExerciseDurationBef3 +
                    dayExerciseDurationBef4 +
                    dayExerciseDurationBef5 +
                    dayExerciseDurationBef6); break;
        }


        // 根据使用周数确定每周目标运动时长（分钟）
        long weekExerciseCompletionRateBef0 = -1;
        System.out.println("今日运动时间: " + dayExerciseDurationBef0 + "分钟");
        System.out.println("昨日运动时间: " + dayExerciseDurationBef1 + "分钟");
        if (totalWeeklyDuration < 0) {
            weekExerciseDurationBef0 = 0;
            totalWeeklyDuration = 0;
        }else {
            weekExerciseDurationBef0 = totalWeeklyDuration;
        }
        System.out.println("本周的运动时长为：" + weekExerciseDurationBef0 + " 分钟");
        System.out.println("totalWeeklyDuration = " + totalWeeklyDuration);
        // 计算达标率（保留两位小数）
        weekExerciseCompletionRateBef0 = totalWeeklyDuration * 100 / currentWeekExerciseIntensity ;

        System.out.println("本周运动目标完成率：" + weekExerciseCompletionRateBef0  + "%");

        if (noticeNumber == 4 && weekExerciseCompletionRateBef0 >= 100 && dayAfterCourseUpdate == 7) {
            exerciseReminderCycle = 2;
            System.out.println("这周的运动量达标了！恢复成每日推送");
            //连续忽略运动次数也清0
            consecutiveExerciseReminderIgnores = 0;
        }
        if (noticeNumber == 4 && weekLearnCompletionRateBef0 >= 100 && dayAfterCourseUpdate == 7) {
            courseReminderCycle = 2;
            System.out.println("这周课程100完成，恢复成每日推送");
            //连续忽略课程次数也清0
            consecutiveCourseReminderIgnores = 0;
        }

        //      ---------------------------------------------------添加数据--------------------------------------------------------
        newInferenceLog.setDeviceId(deviceid);
        newInferenceLog.setRuleIds("");
        newInferenceLog.setContent("");
        //课程类
        newInferenceLog.setUnlearnOverDays(unlearnOverDays);
        newInferenceLog.setLearnStartAfterUpdateHour(learnStartAfterUpdateHour);
        newInferenceLog.setLearnCompletionAfterUpdateDay(learnCompletionAfterUpdateDay);
        newInferenceLog.setCourseCompletionNumber(courseCompletionNumber);
        newInferenceLog.setCourseUncompletionNumber(courseUncompletionNumber);
        newInferenceLog.setWeekLearnCompletionRateBef0(weekLearnCompletionRateBef0);
        newInferenceLog.setAppRegisterDuration(weeksSinceCreation);
        //动态调整难度
//        6天前忽略运动提醒次数
        newInferenceLog.setDayInterfereIgnoreTimesBef0(dayInterfereIgnoreTimesBef0);
        newInferenceLog.setDayInterfereIgnoreTimesBef1(dayInterfereIgnoreTimesBef1);
        newInferenceLog.setDayInterfereIgnoreTimesBef2(dayInterfereIgnoreTimesBef2);
        newInferenceLog.setDayInterfereIgnoreTimesBef3(dayInterfereIgnoreTimesBef3);
        newInferenceLog.setDayInterfereIgnoreTimesBef4(dayInterfereIgnoreTimesBef4);
        newInferenceLog.setDayInterfereIgnoreTimesBef5(dayInterfereIgnoreTimesBef5);
        newInferenceLog.setDayInterfereIgnoreTimesBef6(dayInterfereIgnoreTimesBef6);
//        6日前干预提醒响应率为X
        newInferenceLog.setDayInterfereResponsivityBef0(dayInterfereResponsivityBef0);
        newInferenceLog.setDayInterfereResponsivityBef1(dayInterfereResponsivityBef1);
        newInferenceLog.setDayInterfereResponsivityBef2(dayInterfereResponsivityBef2);
        newInferenceLog.setDayInterfereResponsivityBef3(dayInterfereResponsivityBef3);
        newInferenceLog.setDayInterfereResponsivityBef4(dayInterfereResponsivityBef4);
        newInferenceLog.setDayInterfereResponsivityBef5(dayInterfereResponsivityBef5);
        newInferenceLog.setDayInterfereResponsivityBef6(dayInterfereResponsivityBef6);
//        3周前运动完成率
        newInferenceLog.setWeekExerciseCompletionRateBef0(weekExerciseCompletionRateBef0);
        newInferenceLog.setWeekExerciseCompletionRateBef1(weekExerciseCompletionRateBef1);
        newInferenceLog.setWeekExerciseCompletionRateBef2(weekExerciseCompletionRateBef2);
        newInferenceLog.setWeekExerciseCompletionRateBef3(weekExerciseCompletionRateBef3);
//        6天前是否提前完成当日运动计划
        newInferenceLog.setDayExercisePlanDoneBef0(dayExercisePlanDoneBef0);
        newInferenceLog.setDayExercisePlanDoneBef1(dayExercisePlanDoneBef1);
        newInferenceLog.setDayExercisePlanDoneBef2(dayExercisePlanDoneBef2);
        newInferenceLog.setDayExercisePlanDoneBef3(dayExercisePlanDoneBef3);
        newInferenceLog.setDayExercisePlanDoneBef4(dayExercisePlanDoneBef4);
        newInferenceLog.setDayExercisePlanDoneBef5(dayExercisePlanDoneBef5);
        newInferenceLog.setDayExercisePlanDoneBef6(dayExercisePlanDoneBef6);
//        当日低 中 高等强度运动运动时长X
        newInferenceLog.setDayLowExerciseDurationBef0(dayLowExerciseDurationBef0);
        newInferenceLog.setDayMidExerciseDurationBef0(dayMidExerciseDurationBef0);
        newInferenceLog.setDayHighExerciseDurationBef0(dayHighExerciseDurationBef0);
//        6天前上午活动时长X
        newInferenceLog.setDayAmExerciseDurationBef1(dayAmExerciseDurationBef1);
        newInferenceLog.setDayAmExerciseDurationBef2(dayAmExerciseDurationBef2);
        newInferenceLog.setDayAmExerciseDurationBef3(dayAmExerciseDurationBef3);
        newInferenceLog.setDayAmExerciseDurationBef4(dayAmExerciseDurationBef4);
        newInferenceLog.setDayAmExerciseDurationBef5(dayAmExerciseDurationBef5);
        newInferenceLog.setDayAmExerciseDurationBef6(dayAmExerciseDurationBef6);
//        6天前下午活动时长X
        newInferenceLog.setDayPmExerciseDurationBef1(dayPmExerciseDurationBef1);
        newInferenceLog.setDayPmExerciseDurationBef2(dayPmExerciseDurationBef2);
        newInferenceLog.setDayPmExerciseDurationBef3(dayPmExerciseDurationBef3);
        newInferenceLog.setDayPmExerciseDurationBef4(dayPmExerciseDurationBef4);
        newInferenceLog.setDayPmExerciseDurationBef5(dayPmExerciseDurationBef5);
        newInferenceLog.setDayPmExerciseDurationBef6(dayPmExerciseDurationBef6);
//        上午9-12点完成当日运动量达标度
        newInferenceLog.setDayAmExerciseCompletionBef0(dayAmExerciseCompletionBef0);
//        当日上午活动时长X 当日下午活动时长X
        newInferenceLog.setDayAmExerciseDurationBef0(dayAmExerciseDurationBef0);
        newInferenceLog.setDayPmExerciseDurationBef0(dayPmExerciseDurationBef0);
//        6天前步数
        newInferenceLog.setDayStepBef0(dayStepBef0);
        newInferenceLog.setDayStepBef1(dayStepBef1);
        newInferenceLog.setDayStepBef2(dayStepBef2);
        newInferenceLog.setDayStepBef3(dayStepBef3);
        newInferenceLog.setDayStepBef4(dayStepBef4);
        newInferenceLog.setDayStepBef5(dayStepBef5);
        newInferenceLog.setDayStepBef6(dayStepBef6);
//        6天前运动目标完成率
        newInferenceLog.setDayExerciseCompletionRateBef0(dayExerciseCompletionRateBef0);
        newInferenceLog.setDayExerciseCompletionRateBef1(dayExerciseCompletionRateBef1);
        newInferenceLog.setDayExerciseCompletionRateBef2(dayExerciseCompletionRateBef2);
        newInferenceLog.setDayExerciseCompletionRateBef3(dayExerciseCompletionRateBef3);
        newInferenceLog.setDayExerciseCompletionRateBef4(dayExerciseCompletionRateBef4);
        newInferenceLog.setDayExerciseCompletionRateBef5(dayExerciseCompletionRateBef5);
        newInferenceLog.setDayExerciseCompletionRateBef6(dayExerciseCompletionRateBef6);

        newInferenceLog.setExerciseStartAfterInterfereDuration(exerciseStartAfterInterfereDuration);
        newInferenceLog.setDayExerciseStartTime(dayExerciseStartTime);
        newInferenceLog.setExerciseUncompletionOverDays(exerciseUncompletionOverDays);

        newInferenceLog.setCourseUnlearnHour(courseUnlearnHour);
        if (averageStartTime.isPresent()) {
            newInferenceLog.setDayExerciseAverStartTime(DateUtil.date(averageStartTime.get()));
        }
        newInferenceLog.setCurrentExerciseWeekNumber(currentExerciseWeekNumber);
        newInferenceLog.setDailyInterventionRemindersCount(dailyInterventionRemindersCount);
        newInferenceLog.setDailyInterventionSuccessRemindersCount(dailyInterventionSuccessRemindersCount);
        System.out.println("noticeNumber: " + noticeNumber);
        newInferenceLog.setNoticeNumber(noticeNumber);

        newInferenceLog.setExerciseReminderCycle(exerciseReminderCycle);
        newInferenceLog.setCourseReminderCycle(courseReminderCycle);
        newInferenceLog.setDayAfterCourseUpdate(dayAfterCourseUpdate);
        newInferenceLog.setConsecutiveExerciseReminderIgnores(consecutiveExerciseReminderIgnores);
        newInferenceLog.setConsecutiveCourseReminderIgnores(consecutiveCourseReminderIgnores);
        newInferenceLog.setDailyExerInterventionSucCount(dailyExerInterventionSucCount);
        newInferenceLog.setDailyCourseInterventionSucCount(dailyCourseInterventionSucCount);
        newInferenceLog.setDailyExerInterventionTotalCount(dailyExerInterventionTotalCount);
        newInferenceLog.setDailyCourseInterventionTotalCount(dailyCourseInterventionTotalCount);
        newInferenceLog.setStopExerciseForSecurity(stopExerciseForSecurity);
        //干预成功后将状态重置
        newInferenceLog.setCurrentCourseReminderStatus(currentCourseReminderStatus);
        newInferenceLog.setCurrentExerciseReminderStatus(currentExerciseReminderStatus);


//      ---------------------------------------------------返回数据--------------------------------------------------------

        return newInferenceLog;
    }

    private long isExerciseInterventionResponded( LocalDateTime startTime, LocalDateTime endTime, DeviceInfoVo deviceInfoVo) {

        // 获取12:00-18:00之间的心率数据
        List<DataScheduled> afternoonHeartRateData = dataScheduledMapper.selectList(
            new LambdaQueryWrapper<DataScheduled>()
                .select(DataScheduled::getHr, DataScheduled::getCreateTime)
                .eq(DataScheduled::getDeviceId, deviceInfoVo.getId())
                .ge(DataScheduled::getCreateTime, Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant()))
                .lt(DataScheduled::getCreateTime, Date.from(endTime.atZone(ZoneId.systemDefault()).toInstant()))
        );

        double maxHeartRate = 207 - 0.7 * deviceInfoVo.getAge();
        int lowIntensityDuration = 0;
        int mediumIntensityDuration = 0;
        int highIntensityDuration = 0;

        // 计算各强度运动时长
        for (DataScheduled data : afternoonHeartRateData) {
            int duration = 180; // 每次记录代表3分钟
            double heartRate = data.getHr();
            double heartRatePercentage = heartRate / maxHeartRate;

            if (heartRatePercentage < 0.63 && heartRatePercentage > 0.57) {
                lowIntensityDuration += duration;
            } else if (heartRatePercentage <= 0.76) {
                mediumIntensityDuration += duration;
            } else if (heartRatePercentage >= 0.77){
                highIntensityDuration += duration;
            }
        }
        return mediumIntensityDuration + highIntensityDuration;
    }


    private boolean isCourseInterventionResponed(LocalDateTime startTime, LocalDateTime endTime, DeviceInfoVo deviceInfoVo) {
        // 查询该时间范围内的课程学习记录
        List<CourseStatusVo> courseRecords = courseStatusMapper.selectVoList(
            new LambdaQueryWrapper<CourseStatus>()
                .eq(CourseStatus::getDeviceId, deviceInfoVo.getId())
                .between(CourseStatus::getUpdateTime, startTime, endTime)
        );

        // 检查是否有学习记录且观看时长大于3分钟
        boolean hasValidLearning = courseRecords.stream()
            .anyMatch(record -> record.getCourseViewingDuration() != null && record.getCourseViewingDuration() >= 3);
        return  hasValidLearning;
    }


    /**
     * 计算平均开始学习时间（只计算时分秒部分）
     * @param times
     * @return
     */
    private Optional<LocalDateTime> calculateAverage(List<LocalDateTime> times) {
        if (times == null || times.isEmpty()) {
            return Optional.empty();
        }

        // 将所有时间转换为秒数（从当天0点开始计算）
        long totalSeconds = times.stream()
            .map(time -> time.toLocalTime().toSecondOfDay())
            .reduce(0, Integer::sum);

        long averageSeconds = totalSeconds / times.size();

        // 将平均秒数转换回LocalTime
        LocalTime averageTime = LocalTime.ofSecondOfDay(averageSeconds);

        // 使用今天的日期和计算出的平均时间创建LocalDateTime
        return Optional.of(LocalDateTime.of(LocalDate.from(nowTime), averageTime));
    }

    /**
     * 计算从设备创建时间到当前日期经过的完整周数
     */
    public long calculateWeeksSinceCreation(Date deviceCreateTime) {
        LocalDate createDate = deviceCreateTime.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        LocalDate currentDate = LocalDate.from(nowTime);

        // 计算完整的周数
        return ChronoUnit.DAYS.between(createDate, currentDate) / 7;
    }
    /**
     * 获取某一天的步数
     */
    public long getOneDayLastRecord(LocalDate oneDay, DeviceInfoVo deviceInfoVo) {

// 获取当天早上7:00的时间点
        LocalDateTime startTime = oneDay.atTime(7, 0); // 2025-06-12 07:00:00

// 转换为Date对象（假设需要与旧API兼容）
        Date startOfDay = Date.from(startTime.atZone(ZoneId.systemDefault()).toInstant());
        Date endOfDay = Date.from(nowTime.atZone(ZoneId.systemDefault()).toInstant());
        DataScheduledVo dataScheduledVo = dataScheduledMapper.selectVoOne(new LambdaQueryWrapper<DataScheduled>()
                .eq(DataScheduled::getDeviceId, deviceInfoVo.getId())
                .ge(DataScheduled::getCreateTime, startOfDay)  // 大于等于当天开始
                .lt(DataScheduled::getCreateTime, endOfDay)    // 小于次日开始
                .orderByDesc(DataScheduled::getCreateTime)     // 按时间倒序
                .last("LIMIT 1"));
        long dayStep = 0;
        if (dataScheduledVo != null) {
            dayStep = dataScheduledVo.getStep();
        }
        return dayStep;
    }
//      ---------------------------------------------------运动强度--------------------------------------------------------

    public TodayExerciseData calculateTodayExerciseDuration(DeviceInfoVo deviceInfoVo, long weeksSinceCreation) {
        LocalDate today = LocalDate.from(nowTime);
        LocalDateTime todayStart = today.atTime(7, 0); // 上午7点
        System.out.println("todayStart = " + todayStart);
//        LocalDateTime todayEnd = today.atTime(22, 0); // 下午7点
        // 修改后 - 使用nowTime的时间部分
        LocalDateTime todayEnd = today.atTime(nowTime.getHour(), nowTime.getMinute(), nowTime.getSecond(), nowTime.getNano());
        System.out.println("todayEnd = " + todayEnd);
        // 获取当日心率数据
        List<DataScheduled> todayHeartRateData = dataScheduledMapper.selectList(
                new LambdaQueryWrapper<DataScheduled>()
                        .select(DataScheduled::getId, DataScheduled::getHr, DataScheduled::getCreateTime)
                        .eq(DataScheduled::getDeviceId, deviceInfoVo.getId())
                        .ge(DataScheduled::getCreateTime,
                                Date.from(todayStart.atZone(ZoneId.systemDefault()).toInstant()))
                        .lt(DataScheduled::getCreateTime,
                                Date.from(todayEnd.atZone(ZoneId.systemDefault()).toInstant()))
        );

        double maxHeartRate = 207 - 0.7 * deviceInfoVo.getAge();
        TodayExerciseData todayData = new TodayExerciseData();

        // 查找第一条运动数据
        DataScheduled firstExerciseData = null;
        System.out.println("todayHeartRateData = " + todayHeartRateData);
        for (DataScheduled data : todayHeartRateData) {
            if (data.getHr() >= maxHeartRate * 0.57) {
                firstExerciseData = data;
                break;
            }
        }
        System.out.println("firstExerciseData = " + firstExerciseData);
        if (firstExerciseData != null) {
            dayExerciseStartTime = new DateTime(firstExerciseData.getCreateTime());
            System.out.println("第一条运动数据时间: " + firstExerciseData.getCreateTime());
        } else {
            //数据为空

//            dayExerciseStartTime = DateUtil.parse(DateUtil.today() + " 08:40:00");
        }

        // 初始化上午和下午的运动时长
        int morningExerciseDuration = 0;
        int afternoonExerciseDuration = 0;
        int eveningExerciseDuration = 0;
        int morningExerciseCount = 0;
        int afternoonExerciseCount = 0;
        int eveningExerciseCount = 0;
        List<Date> morningExerciseTimes = new ArrayList<>();
        List<Date> afternoonExerciseTimes = new ArrayList<>();
        List<Date> eveningExerciseTimes = new ArrayList<>();

        // 计算上午和下午,晚上的运动时长
        for (DataScheduled data : todayHeartRateData) {
            LocalDateTime recordTime = data.getCreateTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();

            boolean isMorning = recordTime.getHour() < 12; // 7:00-11:59 属于上午
            boolean isAfternoon = recordTime.getHour() >= 12 && recordTime.getHour() < 16; // 12:00-17:59 属于下午
            int duration = 180; // 每次记录代表3分钟
            double heartRate = data.getHr();
            double heartRatePercentage = heartRate / maxHeartRate;

            ExercisePeriod period;
            if (isMorning) {
                period = todayData.getMorning();
            } else if (isAfternoon) {
                period = todayData.getAfternoon();
            } else {
                period = todayData.getEvening();  // 18:00-21:59 属于晚上
            }

            if (heartRatePercentage <= 0.63 && heartRatePercentage > 0.57) {
                period.addLowIntensityDuration(duration);
            } else if (heartRatePercentage <= 0.76 && heartRatePercentage >= 0.64) {
                period.addMediumIntensityDuration(duration);
            } else if (heartRatePercentage > 0.76) {
                period.addHighIntensityDuration(duration);
            }


            // 判断运动时间属于上午还是下午
            Calendar cal = Calendar.getInstance();
            cal.setTime(data.getCreateTime());
            int hour = cal.get(Calendar.HOUR_OF_DAY);
            if (hour >= 6 && hour < 12) {
                morningExerciseDuration += duration;
                morningExerciseCount++;
                morningExerciseTimes.add(data.getCreateTime());
            } else if (hour >= 12 && hour < 18) {
                afternoonExerciseDuration += duration;
                afternoonExerciseCount++;
                afternoonExerciseTimes.add(data.getCreateTime());
            } else if (hour >= 18 && hour < 22) {
                eveningExerciseDuration += duration;
                eveningExerciseCount++;
                eveningExerciseTimes.add(data.getCreateTime());
            }
        }

        todayData.setMorningExerciseDuration(morningExerciseDuration);
        todayData.setMorningExerciseCount(morningExerciseCount);
        todayData.setMorningExerciseTimes(morningExerciseTimes);
        todayData.setAfternoonExerciseDuration(afternoonExerciseDuration);
        todayData.setAfternoonExerciseCount(afternoonExerciseCount);
        todayData.setAfternoonExerciseTimes(afternoonExerciseTimes);
        todayData.setEveningExerciseDuration(eveningExerciseDuration);
        todayData.setEveningExerciseCount(eveningExerciseCount);
        todayData.setEveningExerciseTimes(eveningExerciseTimes);


        // 计算目标完成率
        int requiredMinutes = (weeksSinceCreation <= 2) ? 15 :
                (weeksSinceCreation <= 4) ? 20 : 30;
        System.out.println("今天的目标运动强度为：" + requiredMinutes + "分钟");
        int requiredSeconds = requiredMinutes * 60;

        // 计算上午完成率
        ExercisePeriod morning = todayData.getMorning();
        // 计算上午运动时长占全天目标的百分比（保留整数部分）
        if (requiredSeconds > 0) { // 避免除零错误
            int completionRate = (int) ((morning.getTotalDuration()* 60 * 100.0) / requiredSeconds);
            morning.setCompletionRate(completionRate);
        } else {
            morning.setCompletionRate(0); // 目标时长为0时默认完成率为0%
        }

        // 计算下午完成率
        ExercisePeriod afternoon = todayData.getAfternoon();
        if (requiredSeconds > 0) { // 避免除零错误
            int completionRate = (int) ((afternoon.getTotalDuration()* 60 * 100.0) / requiredSeconds);
            afternoon.setCompletionRate(completionRate);
        } else {
            afternoon.setCompletionRate(0); // 目标时长为0时默认完成率为0%
        }
        // 计算晚上完成率
        ExercisePeriod evening = todayData.getEvening();
        if (requiredSeconds > 0) { // 避免除零错误
            int completionRate = (int) ((evening.getTotalDuration()* 60 * 100.0) / requiredSeconds);
            evening.setCompletionRate(completionRate);
        } else {
            evening.setCompletionRate(0); // 目标时长为0时默认完成率为0%
        }
        // 计算全天完成率
        int totalDuration = morning.getTotalDuration() + afternoon.getTotalDuration() + evening.getTotalDuration();
        todayData.setTotalDuration(totalDuration);
        if (requiredSeconds > 0) { // 避免除零错误
            // 修改完成率计算逻辑，直接使用总时长除以目标时长
            int completionRate = (int) ((totalDuration * 100.0) / (requiredSeconds/60));
            todayData.setTotalCompletionRate(completionRate);
            System.out.println("总运动时长: " + totalDuration + "分钟, 目标时长: " + requiredSeconds/60 + "分钟, 完成率: " + completionRate + "%");
        } else {
            todayData.setTotalCompletionRate(0); // 目标时长为0时默认完成率为0%
        }


        return todayData;
    }


    // 表示时间段的运动数据（复用之前的类）
    public static class ExercisePeriod {
        private int lowIntensityDuration = 0;  // 修改初始值为0
        private int mediumIntensityDuration = 0;  // 修改初始值为0
        private int highIntensityDuration = 0;  // 修改初始值为0
        private int completionRate = 0;  // 修改初始值为0

        public int getLowIntensityDuration() {
            return lowIntensityDuration / 60; // 将秒转换为分钟
        }
        public void addLowIntensityDuration(int duration) {
            this.lowIntensityDuration += duration;
        }
        public int getMediumIntensityDuration() {
            return mediumIntensityDuration / 60; // 将秒转换为分钟
        }
        public void addMediumIntensityDuration(int duration) {
            this.mediumIntensityDuration += duration;
        }
        public int getHighIntensityDuration() {
            return highIntensityDuration / 60; // 将秒转换为分钟
        }
        public void addHighIntensityDuration(int duration) {
            this.highIntensityDuration += duration;
        }
        public int getTotalDuration() {
            return (lowIntensityDuration + mediumIntensityDuration + highIntensityDuration) / 60; // 将秒转换为分钟
        }
        public int getCompletionRate() { return completionRate; }
        public void setCompletionRate(int completionRate) { this.completionRate = completionRate; }
    }

    // 表示当日运动数据的类
    public static class TodayExerciseData {
        private ExercisePeriod morning = new ExercisePeriod();
        private ExercisePeriod afternoon = new ExercisePeriod();
        private ExercisePeriod evening = new ExercisePeriod();  // 添加晚上的运动时段
        private int totalDuration;
        private int totalCompletionRate;
        private int morningExerciseDuration;
        private int morningExerciseCount;
        private List<Date> morningExerciseTimes;
        private int afternoonExerciseDuration;
        private int afternoonExerciseCount;
        private List<Date> afternoonExerciseTimes;
        private int eveningExerciseDuration;  // 添加晚上的运动时长
        private int eveningExerciseCount;     // 添加晚上的运动次数
        private List<Date> eveningExerciseTimes;  // 添加晚上的运动时间列表

        public ExercisePeriod getMorning() { return morning; }
        public ExercisePeriod getAfternoon() { return afternoon; }
        public ExercisePeriod getEvening() { return evening; }  // 添加晚上的 getter
        public int getTotalDuration() {
            return morning.getTotalDuration() + afternoon.getTotalDuration() + evening.getTotalDuration();
        }
        public void setTotalDuration(int totalDuration) { this.totalDuration = totalDuration; }
        public int getTotalCompletionRate() {
            return totalCompletionRate;
        }
        public void setTotalCompletionRate(int totalCompletionRate) {
            this.totalCompletionRate = totalCompletionRate;
        }
        public int getMorningExerciseDuration() { return morningExerciseDuration; }
        public void setMorningExerciseDuration(int morningExerciseDuration) { this.morningExerciseDuration = morningExerciseDuration; }
        public int getMorningExerciseCount() { return morningExerciseCount; }
        public void setMorningExerciseCount(int morningExerciseCount) { this.morningExerciseCount = morningExerciseCount; }
        public List<Date> getMorningExerciseTimes() { return morningExerciseTimes; }
        public void setMorningExerciseTimes(List<Date> morningExerciseTimes) { this.morningExerciseTimes = morningExerciseTimes; }
        public int getAfternoonExerciseDuration() { return afternoonExerciseDuration; }
        public void setAfternoonExerciseDuration(int afternoonExerciseDuration) { this.afternoonExerciseDuration = afternoonExerciseDuration; }
        public int getAfternoonExerciseCount() { return afternoonExerciseCount; }
        public void setAfternoonExerciseCount(int afternoonExerciseCount) { this.afternoonExerciseCount = afternoonExerciseCount; }
        public List<Date> getAfternoonExerciseTimes() { return afternoonExerciseTimes; }
        public void setAfternoonExerciseTimes(List<Date> afternoonExerciseTimes) { this.afternoonExerciseTimes = afternoonExerciseTimes; }
        public int getEveningExerciseDuration() { return eveningExerciseDuration; }  // 添加晚上的 getter
        public void setEveningExerciseDuration(int eveningExerciseDuration) { this.eveningExerciseDuration = eveningExerciseDuration; }  // 添加晚上的 setter
        public int getEveningExerciseCount() { return eveningExerciseCount; }  // 添加晚上的 getter
        public void setEveningExerciseCount(int eveningExerciseCount) { this.eveningExerciseCount = eveningExerciseCount; }  // 添加晚上的 setter
        public List<Date> getEveningExerciseTimes() { return eveningExerciseTimes; }  // 添加晚上的 getter
        public void setEveningExerciseTimes(List<Date> eveningExerciseTimes) { this.eveningExerciseTimes = eveningExerciseTimes; }  // 添加晚上的 setter
    }


}
